Imports Clo = Enhancements.Core.Logging
Imports Gen = System.Collections.Generic
Imports Glo = System.Globalization
Imports Iou = System.IO
Imports Ref = System.Reflection
Imports Reg = System.Text.RegularExpressions
Imports Sys = System
Imports Tex = System.Text
Imports Xsd = System.Xml.Schema
Imports W3c = System.Xml

Namespace Enhancements.Basic.Primitives
    ''' <summary>Represents a format applicable to a week day part in a System.DateTime instance.</summary>
    <Serializable(), DebuggerStepThrough()> _
    Public NotInheritable Class DateTimeFormatWeekday
        Inherits DateTimeFormat

        ''' <summary>Initializes a DateTimeFormatWeekday instance with default values.</summary>
        Public Sub New()
        End Sub

        ''' <summary>Initializes a DateTimeFormatWeekday instance with defined values.</summary>
        ''' <param name="_startingDay">Week starting day to use.</param>
        ''' <param name="_startingIndex">Week day number offset to apply.</param>
        ''' <exception cref="IsInRangeNotException">_value is lower than 0 or higher than 1.</exception>
        Public Sub New(ByVal _startingDay As DateTimeFormatWeekdayStartingDay, ByVal _startingIndex As Sys.Int32)
            StartingDay = _startingDay
            StartingIndex = _startingIndex
        End Sub

        Private __StartingDay As DateTimeFormatWeekdayStartingDay = DateTimeFormatWeekdayStartingDay.Sunday
        ''' <summary>Gets and sets the week starting day to use. The default value is 'DateTimeFormatWeekdayStartingDays.Sunday'.</summary>
        Public Property StartingDay() As DateTimeFormatWeekdayStartingDay
            Get
                Return __StartingDay
            End Get
            Set(ByVal _value As DateTimeFormatWeekdayStartingDay)
                __StartingDay = _value
            End Set
        End Property

        Private __StartingIndex As System.Int32 = 0
        ''' <summary>Gets and sets the week day number offset to use. The default value is 0.</summary>
        ''' <exception cref="IsInRangeNotException">_value is lower than 0 or higher than 1.</exception>
        Public Property StartingIndex() As System.Int32
            Get
                Return __StartingIndex
            End Get
            Set(ByVal _value As System.Int32)
                _value.IsInRange("StartingIndex._value", 0, 1, True)

                __StartingIndex = _value
            End Set
        End Property

        ''' <summary>Builds a format expression according to the instance values.</summary>
        ''' <returns> </returns>
        Public Overrides Function ExpressionBuild() As System.String
            Dim _returnValueStringBuilder As Tex.StringBuilder = New Tex.StringBuilder(Sys.String.Empty)
            _returnValueStringBuilder.Append(___ExpressionPrefix)
            _returnValueStringBuilder.Append("weekday")
            _returnValueStringBuilder.Append(___ExpressionSeparatorTitleProperties)
            _returnValueStringBuilder.Append("startingDay")
            _returnValueStringBuilder.Append(___ExpressionSeparatorPropertyNameValue)
            _returnValueStringBuilder.Append(StartingDay.ToString().ToLowerInvariant())
            _returnValueStringBuilder.Append(___ExpressionSeparatorProperties)
            _returnValueStringBuilder.Append("startingIndex")
            _returnValueStringBuilder.Append(___ExpressionSeparatorPropertyNameValue)
            _returnValueStringBuilder.Append(StartingIndex.ToString(Glo.CultureInfo.InvariantCulture))
            _returnValueStringBuilder.Append(___ExpressionSeparatorProperties)
            _returnValueStringBuilder.Append(___ExpressionSuffix)

            Return _returnValueStringBuilder.ToString()
        End Function

        ''' <summary>Formats a supplied value according to the instance values.</summary>
        ''' <param name="_value">Value to format.</param>
        ''' <returns> </returns>
        Public Overrides Function Format(ByVal _value As Sys.DateTime) As System.String
            Dim _returnValueInt32 As System.Int32 = 0
            Select Case StartingDay
                Case DateTimeFormatWeekdayStartingDay.Sunday
                    _returnValueInt32 = _value.DayOfWeek
                Case DateTimeFormatWeekdayStartingDay.Monday
                    If _value.DayOfWeek = DayOfWeek.Sunday Then
                        _returnValueInt32 = 0
                    Else
                        _returnValueInt32 = _value.DayOfWeek - 1
                    End If
            End Select
            If StartingIndex = 1 Then
                _returnValueInt32 += 1
            End If

            Return _returnValueInt32.ToString(Glo.CultureInfo.InvariantCulture)
        End Function

        Friend Const ___RegularExpression As System.String = "^{weekday:startingDay=(sunday|monday);startingIndex=(0|1);}$"

        ''' <summary>Tries to parse a format expression, returning an according instance in the _result parameter and True in the return value, when valid. When not, null is put in _result and False is returned.</summary>
        ''' <param name="_expression">Expression to inspect.</param>
        ''' <param name="_result">Instance returned when a valid format expression is used.</param>
        ''' <returns>Whether the operation proceeded normally.</returns>
        Public Shared Function TryParse(ByVal _expression As System.String, ByRef _result As DateTimeFormatWeekday) As System.Boolean
            Dim _returnValue As System.Boolean = False
            Try
                _expression.IsInRegularExpression("_expression", ___RegularExpression, True)
                Dim _startingDay As DateTimeFormatWeekdayStartingDay = CType(Sys.Enum.Parse(GetType(DateTimeFormatWeekdayStartingDay), Reg.Regex.Matches(_expression, ___RegularExpression).Item(0).Groups(1).Value, True), DateTimeFormatWeekdayStartingDay)
                Dim _startingIndex As Sys.Int32 = Sys.Int32.Parse(Reg.Regex.Matches(_expression, ___RegularExpression).Item(0).Groups(2).Value, Glo.CultureInfo.InvariantCulture)
                _result = New DateTimeFormatWeekday(_startingDay, _startingIndex)
                _returnValue = True
            Catch
                _result = Nothing
            End Try

            Return _returnValue
        End Function

    End Class
End Namespace
